package functions;
import types.*;
import clara.CLARA;
import gui.RunCrst;
import java.util.ArrayList;


public class RunMainProcedure {
	public RunMainProcedure() {
	}
	// main program procedure
	public static DataSet MainProcedure(ArrayList<String> data, int sizerest, double samplesize, int numsamples, Boolean std, Boolean maxd, Double maxdt ){	    
		DataSet dataSet = new DataSet(data, sizerest, samplesize, numsamples, std, maxd, maxdt);	
		SubSet mainset = new SubSet(data);	// original data from dataSet
		SubSet[] subsets = new SubSet[2];	// the return subsets from clara
		ArrayList<SubSet> subsetsList =	new ArrayList<SubSet>();
		Boolean ans = true;	// can Partition
		SubSet tempsubset;
		int probarVal=0, nullCnt = 0;
		
		System.gc();
		Tree tree = new Tree(); 
	    int root = 1, treeIndex=0;  
	    
	    // set ProBarMax value
		probarVal +=5;
		RunCrst.setProBarMax(probarVal);
		
		//sub groups T1,T2
		subsets = CLARA.ApplyCLARA(mainset,2,dataSet.getNumSamples(),dataSet.getSampleSize());    //first run of clara to divide data set into 2 sub-sets
		
		//insert first sub groups T1,T2 to the tree
			tree.setCargo (tree.left (root)+treeIndex, subsets[0]);	
			tree.setCargo (tree.right (root)+treeIndex, subsets[1]);
			
			subsetsList.add(tree.getCargo(tree.left(root)+treeIndex));
			subsetsList.add(tree.getCargo(tree.right(root)+treeIndex));
			
			treeIndex++;treeIndex++;
		
		// set ProBarMax value
		probarVal +=5;
		RunCrst.setProBarMax(probarVal);
		
		// build clara tree
		for(int t=2; ( subsetsList.size()<sizerest && nullCnt<sizerest); t++)
		{
			
			// check if node is null, if so add left&right child
			//System.out.println(tree.getCargo(t).getElement(0));
			if(tree.getCargo(t).getElement(0).equals("null")) 
			{
				tree.addNullCargo(tree.left(root)+treeIndex);	//add left null node				
				tree.addNullCargo(tree.right(root)+treeIndex);	//add right null node	
				treeIndex++;treeIndex++;
				nullCnt++;
				
				continue; // next
			}
			nullCnt = 0;
			
			// get the node t from the tree
			tempsubset = new SubSet();
			tempsubset.setElement(tree.getCargo(t));
			tempsubset.setBestMedoid(tree.getCargo(t).getBestMedoid());
			
			// check if the sample bigger than the clusters num
			int checksum = (int)(dataSet.getSampleSize()*tempsubset.getSize())/100;
			//System.out.println(checksum);
			if( checksum < 4)	
			{
				//subsetsList.add(tree.getCargo(t));
				
				tree.addNullCargo(tree.left(root)+treeIndex);	//add left null node				
				tree.addNullCargo(tree.right(root)+treeIndex);	//add right null node
				treeIndex++;treeIndex++;
				
				continue;
			}
			
			// run clara
			subsets = CLARA.ApplyCLARA(tempsubset,2,dataSet.getNumSamples(),dataSet.getSampleSize()); 
			
			// set ProBarMax value
			if(probarVal<94)	probarVal +=5;
			RunCrst.setProBarMax(probarVal);
			
			// stop criteria
			if(std==true)	
				ans = stopCriteriaSTD( subsets[0], subsets[1] );
			else // eps stop criteria
				ans = stopCriteriaEPS( subsets[0].getBestMedoid(), subsets[1].getBestMedoid(), maxdt );
			//
			
			if (ans)	//=true
			{	
				tree.setCargo (tree.left(root)+treeIndex, subsets[0]);
				tree.setCargo (tree.right(root)+treeIndex, subsets[1]);
				
				// add to final subsets
				subsetsList.remove(tree.getCargo(t));
				subsetsList.add(tree.getCargo(tree.left(root)+treeIndex));
				subsetsList.add(tree.getCargo(tree.right(root)+treeIndex));
				
				treeIndex++;treeIndex++;
				
				// set null node
				tree.setNullCargo(t);
			}
			else	//ans=false
			{			
				tree.addNullCargo(tree.left(root)+treeIndex);	//add left null node				
				tree.addNullCargo(tree.right(root)+treeIndex);	//add right null node	
				
				treeIndex++;treeIndex++;
			}

			System.gc(); 

		}//end for
		
		// need to add outliers
		dataSet.setSubSets(subsetsList);
		FinalTest[] finalSet = CreateFinalOutput.GetRepresentingSet(dataSet, subsetsList);
		dataSet.setFinalTests(finalSet);
		
		// set ProBarMax value
		if(probarVal<100) 	probarVal=100; //100%
		RunCrst.setProBarMax(probarVal);
		
		
		
		return dataSet;
		
	}//end MainProcedure
	
	
	
	
	// get answer if make the partition or not by standard deviation
	public static Boolean stopCriteriaSTD(SubSet set1, SubSet set2)
	{
		double n=0.2;
		double std1 = STD.getSTD(set1);
		double std2 = STD.getSTD(set2);
		double ncd = NCD.getNCD(set1.getBestMedoid(), set2.getBestMedoid());
		if( ncd > n*(std1 + std2) )
			return true;
		else
			return false;		
	}
	
	// get answer if make the partition or not by maximal distance
	public static Boolean stopCriteriaEPS(String medoid1, String medoid2, Double eps)
	{
		Double ncdVal = NCD.getNCD(medoid1, medoid2);
		
		if( ncdVal > 2*eps )
			return true;
		else
			return false;
	}
	
	
	
}//end class
